ImapAgent: Replace invalid bytes in a subject or body.

This should fix #733.

Akinori MUSHA 10 years ago
parent
commit
5211378131
2 changed files with 51 additions and 8 deletions
  1. 21 7
      app/models/agents/imap_folder_agent.rb
  2. 30 1
      spec/models/agents/imap_folder_agent_spec.rb

+ 21 - 7
app/models/agents/imap_folder_agent.rb

@@ -240,7 +240,7 @@ module Agents
240 240
           when 'subject'
241 241
             value.present? or next true
242 242
             re = Regexp.new(value)
243
-            if m = re.match(mail.subject)
243
+            if m = re.match(mail.scrubbed(:subject))
244 244
               m.names.each { |name|
245 245
                 matches[name] = m[name]
246 246
               }
@@ -252,7 +252,7 @@ module Agents
252 252
             value.present? or next true
253 253
             re = Regexp.new(value)
254 254
             matched_part = body_parts.find { |part|
255
-               if m = re.match(part.decoded)
255
+               if m = re.match(part.scrubbed(:decoded))
256 256
                  m.names.each { |name|
257 257
                    matches[name] = m[name]
258 258
                  }
@@ -285,7 +285,7 @@ module Agents
285 285
 
286 286
           if matched_part
287 287
             mime_type = matched_part.mime_type
288
-            body = matched_part.decoded
288
+            body = matched_part.scrubbed(:decoded)
289 289
           else
290 290
             mime_type = 'text/plain'
291 291
             body = ''
@@ -295,7 +295,7 @@ module Agents
295 295
 
296 296
           create_event :payload => {
297 297
             'folder' => mail.folder,
298
-            'subject' => mail.subject,
298
+            'subject' => mail.scrubbed(:subject),
299 299
             'from' => mail.from_addrs.first,
300 300
             'to' => mail.to_addrs,
301 301
             'cc' => mail.cc_addrs,
@@ -504,6 +504,15 @@ module Agents
504 504
 
505 505
       attr_reader :uid, :folder, :uidvalidity
506 506
 
507
+      module Scrubbed
508
+        def scrubbed(method)
509
+          (@scrubbed ||= {})[method.to_sym] ||=
510
+            __send__(method).scrub { |bytes| "<#{bytes.unpack('H*')[0]}>" }
511
+        end
512
+      end
513
+
514
+      include Scrubbed
515
+
507 516
       def initialize(client, fetch_data, props = {})
508 517
         @client = client
509 518
         props.each { |key, value|
@@ -538,9 +547,14 @@ module Agents
538 547
           mail.all_parts
539 548
         else
540 549
           [mail]
541
-        end.reject { |part|
542
-          part.multipart? || part.attachment? || !part.text? ||
543
-            !mime_types.include?(part.mime_type)
550
+        end.select { |part|
551
+          if part.multipart? || part.attachment? || !part.text? ||
552
+             !mime_types.include?(part.mime_type)
553
+            false
554
+          else
555
+            part.extend(Scrubbed)
556
+            true
557
+          end
544 558
         }
545 559
       end
546 560
 

+ 30 - 1
spec/models/agents/imap_folder_agent_spec.rb

@@ -36,8 +36,12 @@ describe Agents::ImapFolderAgent do
36 36
             all_parts.find { |part|
37 37
               part.mime_type == type
38 38
             }
39
-          }.compact
39
+          }.compact.map! { |part|
40
+            part.extend(Agents::ImapFolderAgent::Message::Scrubbed)
41
+          }
40 42
         end
43
+
44
+        include Agents::ImapFolderAgent::Message::Scrubbed
41 45
       }
42 46
 
43 47
       @mails = [
@@ -255,4 +259,29 @@ describe Agents::ImapFolderAgent do
255 259
       end
256 260
     end
257 261
   end
262
+
263
+  describe 'Agents::ImapFolderAgent::Message::Scrubbed' do
264
+    before do
265
+      @class = Class.new do
266
+        def subject
267
+          "broken\xB7subject\xB6"
268
+        end
269
+
270
+        def body
271
+          "broken\xB7body\xB6"
272
+        end
273
+
274
+        include Agents::ImapFolderAgent::Message::Scrubbed
275
+      end
276
+
277
+      @object = @class.new
278
+    end
279
+
280
+    describe '#scrubbed' do
281
+      it 'should return a scrubbed string' do
282
+        expect(@object.scrubbed(:subject)).to eq("broken<b7>subject<b6>")
283
+        expect(@object.scrubbed(:body)).to eq("broken<b7>body<b6>")
284
+      end
285
+    end
286
+  end
258 287
 end